/*
 * Copyright (C) 2009 M. Hautle.
 * 
 * This file is part of TrackedBean.
 * 
 * TrackedBean is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * TrackedBean is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with TrackedBean. If not, see <http://www.gnu.org/licenses/>.
 */
package ch.trackedbean.copier.engine;

import java.beans.*;
import java.util.*;
import ch.trackedbean.common.*;
import ch.trackedbean.copier.*;
import ch.trackedbean.util.*;

/**
 * Factory/Configurator for configuring {@link BeanMapper}s manually.<br>
 * Use this factory to create and configure a {@link BeanMapper} by code.<br>
 * Consider to use the {@link BeanMapperManager} and a declarative field mapping.<br>
 * You may reuse a factory simply by creating a new mapper over {@link #createMapper(Class, Class)}.
 * 
 * @author M. Hautle
 */
public class BeanMapperConfigurator {
	/** The bean mapper to configure. */
	protected BeanMapper beanMapper;

	/** Set holding the property names of properties were no default mapping has to be defined. */
	protected final Set<String> noDefaultMapping = new HashSet<String>();

	/** Map caching the properties of used classes. */
	protected final Map<Class, Map<String, PropertyDescriptor>> properties = new HashMap<Class, Map<String, PropertyDescriptor>>();

	/**
	 * Creates a factory to configure a mapper for the given destination type.
	 * 
	 * @param dstType The destination type of the mapper
	 * @return A factory to build the mapper
	 */
	public static BeanMapperConfigurator create(Class dstType) {
		return create(null, dstType);
	}

	/**
	 * Creates a factory to configure a mapper for the given destination type.
	 * 
	 * @param baseType The mapped type (may be null)
	 * @param dstType The destination type of the mapper
	 * @return A factory to build the mapper
	 */
	public static BeanMapperConfigurator create(Class baseType, Class dstType) {
		return new BeanMapperConfigurator().createMapper(baseType, dstType);
	}

	/**
	 * Creates a new mapper for the specified type.
	 * 
	 * @param baseType The mapped type (may be null)
	 * @param dstType The destination type of the mapper
	 * @return The factory
	 */
	public BeanMapperConfigurator createMapper(Class baseType, Class dstType) {
		setBeanMapper(new BeanMapper(baseType, dstType));
		return this;
	}

	/**
	 * Sets the mapper to configure with this
	 * 
	 * @param mapper The mapper to configure
	 */
	public void setCurrentMapper(BeanMapper mapper) {
		beanMapper = mapper;
	}

	/**
	 * Returns the mapper
	 * 
	 * @return The mapper
	 */
	public BeanMapper getBeanMapper() {
		return beanMapper;
	}

	/**
	 * @param beanMapper The beanMapper to set.
	 */
	public void setBeanMapper(BeanMapper beanMapper) {
		this.beanMapper = beanMapper;
		noDefaultMapping.clear();
		properties.clear();
	}

	/**
	 * Adds a simple mapping for the given property name based on the passed mapping type.
	 * 
	 * @param srcType The type of the source bean
	 * @param srcProperty The name of the property in the source type
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addSimpleMapping(Class<?> srcType, String srcProperty, String dstProperty) {
		return addSimpleMapping(srcType, srcProperty, dstProperty, (IPropertyConverter) null, false);
	}

	/**
	 * Adds a root (the source object will be directly mapped using an {@link SelfAccessor}) mapping for the given property name.<br>
	 * This is a read only mapping.
	 * 
	 * @param srcType The type of the source bean
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param converter The converter to use or null
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addSimpleMapping(Class<?> srcType, String dstProperty, Class<? extends IPropertyConverter> converter) {
		return addSimpleMapping(srcType, dstProperty, createInstance(converter));
	}

	/**
	 * Adds a root (the source object will be directly mapped using an {@link SelfAccessor}) mapping for the given property name.<br>
	 * This is a read only mapping.
	 * 
	 * @param srcType The type of the source bean
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param converter The converter to use or null
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addSimpleMapping(Class<?> srcType, String dstProperty, IPropertyConverter converter) {
		noDefaultMapping.add(dstProperty);
		final PropertyDescriptor dst = getDescriptor(beanMapper.getDstType(), dstProperty);
		if (converter == null && !srcType.equals(dst.getPropertyType()))
			throw new MapperInitialisationException("The source type and " + dstProperty + " must be of the same type or a converter must be passed!");
		beanMapper.addMapping(srcType, dstProperty, new SimpleMappingHolder(dst, converter, false));
		return this;
	}

	/**
	 * Adds a simple mapping for the given property name based on the passed mapping type.
	 * 
	 * @param srcType The type of the source bean
	 * @param srcProperty The name of the property in the source type
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param readOnly Flag indicating if the mapping should be 'readonly' so that {@link IBeanMapper#copyDst2Src(Object, Object, IMappingContext)} will not be
	 *            executed
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addSimpleMapping(Class<?> srcType, String srcProperty, String dstProperty, boolean readOnly) {
		return addSimpleMapping(srcType, srcProperty, dstProperty, (IPropertyConverter) null, readOnly);
	}

	/**
	 * Adds a simple mapping for the given property name based on the passed mapping type.
	 * 
	 * @param srcType The type of the source bean
	 * @param srcProperty The name of the property in the source type
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param converter The converter to use or null
	 * @param readOnly Flag indicating if the mapping should be 'readonly' so that {@link IBeanMapper#copyDst2Src(Object, Object, IMappingContext)} will not be
	 *            executed
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addSimpleMapping(Class<?> srcType, String srcProperty, String dstProperty, Class<? extends IPropertyConverter> converter,
			boolean readOnly) {
		return addSimpleMapping(srcType, srcProperty, dstProperty, createInstance(converter), readOnly);
	}

	/**
	 * Adds a simple mapping for the given property name based on the passed mapping type.
	 * 
	 * @param srcType The type of the source bean
	 * @param srcProperty The name of the property in the source type
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param converter The converter to use or null
	 * @param readOnly Flag indicating if the mapping should be 'readonly' so that {@link IBeanMapper#copyDst2Src(Object, Object, IMappingContext)} will not be
	 *            executed
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addSimpleMapping(Class<?> srcType, String srcProperty, String dstProperty, IPropertyConverter converter, boolean readOnly) {
		noDefaultMapping.add(dstProperty);
		final PropertyDescriptor src = getDescriptor(srcType, srcProperty);
		final PropertyDescriptor dst = getDescriptor(beanMapper.getDstType(), dstProperty);
		if (converter == null && !src.getPropertyType().equals(dst.getPropertyType()))
			throw new MapperInitialisationException("The properties " + srcProperty + " and " + dstProperty
					+ " must be of the same type or a converter must be passed!");
		beanMapper.addMapping(srcType, dstProperty, new SimpleMappingHolder(src, dst, converter, readOnly, false));
		return this;
	}

	/**
	 * Adds a deep mapping for the given property name based on the defined type.
	 * 
	 * @param srcType The type of the source bean
	 * @param srcProperty The name of the property in the source type
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param overrideSrc Flag indicating if {@link DeepMappingHolder#copySrc2Dst(Object, Object, IMappingContext)} should override an object hold by the source
	 *            property
	 * @param overrideDst Flag indicating if {@link DeepMappingHolder#copyDst2Src(Object, Object, IMappingContext)} should override an object hold by the
	 *            destination property
	 * @param srcEvaluator The type evaluator to use for {@link DeepMappingHolder#copyToSource(Object, Object, IMappingContext)} or null
	 * @param dstEvaluator The type evaluator to use for {@link DeepMappingHolder#copyToDestination(Object, Object, IMappingContext)} or null
	 * @param readOnly Flag indicating if the mapping should be 'readonly' so that {@link IBeanMapper#copyDst2Src(Object, Object, IMappingContext)} will not be
	 *            executed
	 * @param lazy Flag indicating if the property should be fetched lazy
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addDeepMapping(Class<?> srcType, String srcProperty, String dstProperty, boolean overrideSrc, boolean overrideDst,
			Class<? extends ITypeEvaluator> srcEvaluator, Class<? extends ITypeEvaluator> dstEvaluator, boolean readOnly, boolean lazy) {
		return addDeepMapping(srcType, srcProperty, dstProperty, overrideSrc, overrideDst, createInstance(srcEvaluator), createInstance(dstEvaluator),
				readOnly, lazy);
	}

	/**
	 * Adds a deep mapping for the given property name based on the defined type.
	 * 
	 * @param srcType The type of the source bean
	 * @param srcProperty The name of the property in the source type
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param overrideSrc Flag indicating if {@link DeepMappingHolder#copySrc2Dst(Object, Object, IMappingContext)} should override an object hold by the source
	 *            property
	 * @param overrideDst Flag indicating if {@link DeepMappingHolder#copyDst2Src(Object, Object, IMappingContext)} should override an object hold by the
	 *            destination property
	 * @param srcEvaluator The type evaluator to use for {@link DeepMappingHolder#copyToSource(Object, Object, IMappingContext)} or null
	 * @param dstEvaluator The type evaluator to use for {@link DeepMappingHolder#copyToDestination(Object, Object, IMappingContext)} or null
	 * @param readOnly Flag indicating if the mapping should be 'readonly' so that {@link IBeanMapper#copyDst2Src(Object, Object, IMappingContext)} will not be
	 *            executed
	 * @param lazy Flag indicating if the property should be fetched lazy
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addDeepMapping(Class<?> srcType, String srcProperty, String dstProperty, boolean overrideSrc, boolean overrideDst,
			ITypeEvaluator srcEvaluator, ITypeEvaluator dstEvaluator, boolean readOnly, boolean lazy) {
		noDefaultMapping.add(dstProperty);
		final PropertyDescriptor srcProp = getDescriptor(srcType, srcProperty);
		final PropertyDescriptor dstProp = getDescriptor(beanMapper.getDstType(), dstProperty);
		beanMapper.addMapping(srcType, dstProperty, new DeepMappingHolder(srcProp, dstProp, overrideSrc, overrideDst, srcEvaluator, dstEvaluator, readOnly,
				lazy));
		return this;
	}

	/**
	 * Adds a deep path mapping for the given property name based on the defined {@link IBeanMapper#getMappedBaseType()}.
	 * 
	 * @param srcType The type of the source bean
	 * @param path The path to the source property
	 * @param targetType The type of the value reurned by the el expression
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param overrideSrc Flag indicating if {@link DeepMappingHolder#copySrc2Dst(Object, Object, IMappingContext)} should override an object hold by the source
	 *            property
	 * @param overrideDst Flag indicating if {@link DeepMappingHolder#copyDst2Src(Object, Object, IMappingContext)} should override an object hold by the
	 *            destination property
	 * @param srcEvaluator The type evaluator to use for {@link DeepMappingHolder#copyToSource(Object, Object, IMappingContext)} or null
	 * @param dstEvaluator The type evaluator to use for {@link DeepMappingHolder#copyToDestination(Object, Object, IMappingContext)} or null
	 * @param readOnly Flag indicating if the mapping should be 'readonly' so that {@link IBeanMapper#copyDst2Src(Object, Object, IMappingContext)} will not be
	 *            executed
	 * @param lazy Flag indicating if the property should be fetched lazy
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addDeepPathMapping(Class<?> srcType, String path, Class targetType, String dstProperty, boolean overrideSrc,
			boolean overrideDst, Class<? extends ITypeEvaluator> srcEvaluator, Class<? extends ITypeEvaluator> dstEvaluator, boolean readOnly, boolean lazy) {
		return addDeepPathMapping(srcType, path, targetType, dstProperty, overrideSrc, overrideDst, createInstance(srcEvaluator), createInstance(dstEvaluator),
				readOnly, lazy);
	}

	/**
	 * Adds a deep path mapping for the given property name based on the defined {@link IBeanMapper#getMappedBaseType()}.
	 * 
	 * @param srcType The type of the source bean
	 * @param path The path to the source property
	 * @param targetType The type of the value reurned by the el expression
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param overrideSrc Flag indicating if {@link DeepMappingHolder#copySrc2Dst(Object, Object, IMappingContext)} should override an object hold by the source
	 *            property
	 * @param overrideDst Flag indicating if {@link DeepMappingHolder#copyDst2Src(Object, Object, IMappingContext)} should override an object hold by the
	 *            destination property
	 * @param srcEvaluator The type evaluator to use for {@link DeepMappingHolder#copyToSource(Object, Object, IMappingContext)} or null
	 * @param dstEvaluator The type evaluator to use for {@link DeepMappingHolder#copyToDestination(Object, Object, IMappingContext)} or null
	 * @param readOnly Flag indicating if the mapping should be 'readonly' so that {@link IBeanMapper#copyDst2Src(Object, Object, IMappingContext)} will not be
	 *            executed
	 * @param lazy Flag indicating if the property should be fetched lazy
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addDeepPathMapping(Class<?> srcType, String path, Class targetType, String dstProperty, boolean overrideSrc,
			boolean overrideDst, ITypeEvaluator srcEvaluator, ITypeEvaluator dstEvaluator, boolean readOnly, boolean lazy) {
		noDefaultMapping.add(dstProperty);
		final PropertyDescriptor dstProp = getDescriptor(beanMapper.getDstType(), dstProperty);
		beanMapper.addMapping(srcType, dstProperty, new DeepMappingHolder(path, targetType, dstProp, overrideSrc, overrideDst, srcEvaluator, dstEvaluator,
				readOnly, lazy));
		return this;
	}

	/**
	 * Adds a list mapping for the given property name based on the bassed type.
	 * 
	 * @param srcType The type of the source bean
	 * @param srcProperty The name of the property in the source type
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param dstType The content type of the destination list
	 * @param lazy Flag indicating if the property should be fetched lazy
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addStaticListMapping(Class<?> srcType, String srcProperty, String dstProperty, Class<?> dstType, boolean lazy) {
		return addListMapping(srcType, srcProperty, dstProperty, new StaticEvaluator(dstType), lazy);
	}

	/**
	 * Adds a path list mapping for the given property name based on the passed type.
	 * 
	 * @param srcType The type of the source bean
	 * @param path The path to the source property
	 * @param targetType The type of the value reurned by the el expression
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param dstType The content type of the destination list
	 * @param lazy Flag indicating if the property should be fetched lazy
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addStaticListMapping(Class<?> srcType, String path, Class targetType, String dstProperty, Class<?> dstType, boolean lazy) {
		return addListMapping(srcType, path, targetType, dstProperty, new StaticEvaluator(dstType), lazy);
	}

	/**
	 * Adds a list mapping for the given property name based on the bassed type.
	 * 
	 * @param srcType The type of the source bean
	 * @param srcProperty The name of the property in the source type
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param srcEvaluator The type evaluator to use for {@link DeepMappingHolder#copyToSource(Object, Object, IMappingContext)}
	 * @param lazy Flag indicating if the property should be fetched lazy
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addListMapping(Class<?> srcType, String srcProperty, String dstProperty, Class<? extends ITypeEvaluator> srcEvaluator,
			boolean lazy) {
		return addListMapping(srcType, srcProperty, dstProperty, createInstance(srcEvaluator), lazy);
	}

	/**
	 * Adds a path list mapping for the given property name based on the passed type.
	 * 
	 * @param srcType The type of the source bean
	 * @param path The path to the source property
	 * @param targetType The type of the value reurned by the el expression
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param srcEvaluator The type evaluator to use for {@link DeepMappingHolder#copyToSource(Object, Object, IMappingContext)}
	 * @param lazy Flag indicating if the property should be fetched lazy
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addListMapping(Class<?> srcType, String path, Class targetType, String dstProperty,
			Class<? extends ITypeEvaluator> srcEvaluator, boolean lazy) {
		return addListMapping(srcType, path, targetType, dstProperty, createInstance(srcEvaluator), lazy);
	}

	/**
	 * Adds a list mapping for the given property name based on the bassed type.
	 * 
	 * @param srcType The type of the source bean
	 * @param srcProperty The name of the property in the source type
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param srcEvaluator The type evaluator to use for {@link DeepMappingHolder#copyToSource(Object, Object, IMappingContext)}
	 * @param lazy Flag indicating if the property should be fetched lazy
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addListMapping(Class<?> srcType, String srcProperty, String dstProperty, ITypeEvaluator srcEvaluator, boolean lazy) {
		noDefaultMapping.add(dstProperty);
		final PropertyDescriptor srcProp = getDescriptor(srcType, srcProperty);
		final PropertyDescriptor dstProp = getDescriptor(beanMapper.getDstType(), dstProperty);
		beanMapper.addMapping(srcType, dstProperty, new ListMappingHolder(srcProp, dstProp, srcEvaluator, lazy));
		return this;
	}

	/**
	 * Adds a path list mapping for the given property name based on the passed type.
	 * 
	 * @param srcType The type of the source bean
	 * @param path The path to the source property
	 * @param targetType The type of the value reurned by the el expression
	 * @param dstProperty The property name in the type for which the mapper is built (type on which the annotations were defined)
	 * @param srcEvaluator The type evaluator to use for {@link DeepMappingHolder#copyToSource(Object, Object, IMappingContext)}
	 * @param lazy Flag indicating if the property should be fetched lazy
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addListMapping(Class<?> srcType, String path, Class targetType, String dstProperty, ITypeEvaluator srcEvaluator, boolean lazy) {
		noDefaultMapping.add(dstProperty);
		final PropertyDescriptor dstProp = getDescriptor(beanMapper.getDstType(), dstProperty);
		beanMapper.addMapping(srcType, dstProperty, new ListMappingHolder(path, targetType, dstProp, srcEvaluator, lazy));
		return this;
	}

	/**
	 * Adds a path mapping.
	 * 
	 * @param srcType The type of the source bean
	 * @param property The destination property
	 * @param src The source class
	 * @param path The path starting at the source class
	 * @param readOnly Flag indicating if the mapping should be 'readonly' so that {@link IBeanMapper#copyDst2Src(Object, Object, IMappingContext)} will not be
	 *            executed
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addPathMapping(Class<?> srcType, String property, Class src, String path, boolean readOnly) {
		return addPathMapping(srcType, property, src, path, (IPropertyConverter) null, readOnly);
	}

	/**
	 * Adds a path mapping.
	 * 
	 * @param srcType The type of the source bean
	 * @param property The destination property
	 * @param src The source class
	 * @param path The path starting at the source class
	 * @param converter The converter to use or null
	 * @param readOnly Flag indicating if the mapping should be 'readonly' so that {@link IBeanMapper#copyDst2Src(Object, Object, IMappingContext)} will not be
	 *            executed
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addPathMapping(Class<?> srcType, String property, Class src, String path, Class<? extends IPropertyConverter> converter,
			boolean readOnly) {
		return addPathMapping(srcType, property, src, path, createInstance(converter), readOnly);
	}

	/**
	 * Adds a path mapping.
	 * 
	 * @param srcType The type of the source bean
	 * @param property The destination property
	 * @param src The source class
	 * @param path The path starting at the source class
	 * @param converter The converter to use or null
	 * @param readOnly Flag indicating if the mapping should be 'readonly' so that {@link IBeanMapper#copyDst2Src(Object, Object, IMappingContext)} will not be
	 *            executed
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addPathMapping(Class<?> srcType, String property, Class src, String path, IPropertyConverter converter, boolean readOnly) {
		noDefaultMapping.add(property);
		final PropertyDescriptor dstDesc = getDescriptor(beanMapper.getDstType(), property);
		beanMapper.addMapping(srcType, property, new SimpleMappingHolder(path, dstDesc, converter, readOnly, false));
		return this;
	}

	/**
	 * Adds a default mapping of the given property if it's not allready mapped.
	 * 
	 * @param property The destination property
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addDefaultMapping(String property) {
		return addDefaultMapping(property, false);
	}

	/**
	 * Adds a default mapping of the given property if it's not allready mapped.
	 * 
	 * @param property The destination property
	 * @param readOnly Flag indicating if the mapping should be 'readonly' so that {@link IBeanMapper#copyDst2Src(Object, Object, IMappingContext)} will not be
	 *            executed
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addDefaultMapping(String property, boolean readOnly) {
		final Class base = beanMapper.getMappedBaseType();
		if (base != null && !noDefaultMapping.contains(property))
			addSimpleMapping(base, property, property, readOnly);
		return this;
	}

	/**
	 * Adds the default mappings for the base type if the property is not allready mapped for the type and if it's not on the ignore list.
	 * 
	 * @param ignore The properties to ignore
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addDefaultMappings(String... ignore) {
		return addDefaultMappings(beanMapper.getMappedBaseType(), false, ignore);
	}

	/**
	 * Adds the default mappings for the given type if the property is not allready mapped for the type and if it's not on the ignore list.
	 * 
	 * @param type The base type
	 * @param readOnly Flag indicating if the mapping should be 'readonly' so that {@link IBeanMapper#copyDst2Src(Object, Object, IMappingContext)} will not be
	 *            executed
	 * @param ignore The properties to ignore
	 * @return The factory itself
	 */
	public BeanMapperConfigurator addDefaultMappings(Class type, boolean readOnly, String... ignore) {
		try {
			final Set<String> exclude = new HashSet<String>(noDefaultMapping);
			Collections.addAll(exclude, ignore);
			// process all properties of the specified type
			for (PropertyDescriptor d : Introspector.getBeanInfo(type).getPropertyDescriptors()) {
				final String name = d.getName();
				if (!exclude.contains(name))
					addSimpleMapping(type, name, name, readOnly);
			}
			return this;
		} catch (IntrospectionException e) {
			throw new MapperInitialisationException("Error while adding default properties", e);
		}
	}

	/**
	 * Adds the property to the ignore list.<br>
	 * Ensures that a call of {@link #addDefaultMapping(String)} does nothig.
	 * 
	 * @param property The property name
	 */
	public void ignoreMapping(String property) {
		noDefaultMapping.add(property);
	}

	/**
	 * Returns the descriptor of a given property.
	 * 
	 * @param type The type
	 * @param property The property name
	 * @return The descriptor of the given property
	 * @throws MapperInitialisationException If something goes wrong
	 */
	protected PropertyDescriptor getDescriptor(Class type, String property) throws MapperInitialisationException {
		Map<String, PropertyDescriptor> props = properties.get(type);
		if (props == null)
			properties.put(type, props = BeanUtils.getProperties(type));
		final PropertyDescriptor prop = props.get(property);
		if (prop == null)
			throw new MapperInitialisationException("The property " + property + " doese not exists in " + type.getName() + "!");
		return prop;
	}

	/**
	 * Creates an instance of the given class.
	 * 
	 * @param <T> The type
	 * @param type The type or null
	 * @return An instance of the given type or null
	 */
	@SuppressWarnings("null")
	protected <T> T createInstance(Class<T> type) {
		try {
			return type != null ? type.newInstance() : null;
		} catch (Exception e) {
			throw new MapperInitialisationException("Error while instanciating " + type.getName() + "!", e);
		}
	}

	/**
	 * Cleans up the configurator.
	 */
	public void cleanUp() {
		properties.clear();
		noDefaultMapping.clear();
	}

	/**
	 * Simple evaluator returning an defined type.
	 * 
	 * @author M. Hautle
	 */
	private static class StaticEvaluator implements ITypeEvaluator {
		/** The type to return */
		private final Class<?> type;

		/**
		 * Default constructor.
		 * 
		 * @param type The type
		 */
		public StaticEvaluator(Class<?> type) {
			this.type = type;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public Class<?> getCorrespondingType(Object src) throws TechnicalException {
			return type;
		}
	}
}
